import cats.effect.unsafe.implicits.global
import cats.effect.{IO, Sync}
import com.rock.securityresearch.common.TimePeriod
import com.rock.securityresearch.common.equity.financereport.{FinanceReport, FinanceReportType, FinanceReports}
import com.rock.securityresearch.controller.{Api, ApiResult, Controller, StockController}
import com.rock.securityresearch.domain.DateRange
import com.rock.securityresearch.entity.Stock
import com.rock.securityresearch.equity.{HistoricalStockQuote, QuotePriceCsvParser, StockCode, Stocks}
import com.rock.securityresearch.service.StockService
import com.rock.securityresearch.statistic.Stastistic
import com.rock.securityresearch.util.http.{Http, HttpResponse}
import com.rock.securityresearch.util.{JsonUtil, PrintUtil}
import com.rock.securityresearch.domain.{DateRange, RangeType}


import io.circe.generic.auto.*
import io.circe.parser.*
import org.typelevel.log4cats.Logger
import org.typelevel.log4cats.slf4j.Slf4jLogger
import spark.Spark.*
import spark.route.HttpMethod
import spark.{Request, Response}

import java.time.LocalDate
import java.util.concurrent.Executors
import scala.concurrent.ExecutionContext

@main
def main: Unit = {
    initRoutes()
  // testJson()
}


def initRoutes(): Unit ={
    implicit def logger[F[_] : Sync]: Logger[F] = Slf4jLogger.getLogger[F]

    port(9999)
    before((req, res) => {
        req.attribute("startTime", System.currentTimeMillis())
        Logger[IO].info(s"[APIRequest Begin] Get ${req.pathInfo()}").unsafeRunSync()
    })
    after((req, res) => {
        val start: Long = req.attribute("startTime")
        val end: Long = System.currentTimeMillis()
        Logger[IO].info(s"[APIRequest End] Get ${req.pathInfo()}, status code: ${res.status()}, cost: ${end - start} ms ").unsafeRunSync()
        res.header("Content-Type", "application/json")
    })

    get("/stock/:code", (req, res) => { // http://localhost:9999/stock/601398,601399
        val code = req.params(":code").split(",").map(e => StockCode(e)).toList
        val startDate = Option(req.queryParams("startDate")).map(e => LocalDate.parse(e)).getOrElse(LocalDate.now().minusDays(11))
        val endDate = Option(req.queryParams("endDate")).map(e => LocalDate.parse(e)).getOrElse(LocalDate.now())
        val period = Option(req.queryParams("period")).map(e => TimePeriod(e, TimePeriod.Daily)).getOrElse(TimePeriod.Daily)

        val rangeType = Option(req.queryParams("range_type")).map(e => RangeType(e)).getOrElse(RangeType.Custom)

        val result = for {
            stocks <- StockService.make[IO](Stocks.make[IO]()).getQuotePrice(code, DateRange(startDate, endDate), rangeType, period).attempt
            resBody <- IO {
                stocks match
                    case Left(err: Throwable) => {
                        err.printStackTrace()
                        JsonUtil.toJson(Map("error" -> err.toString))
                    }
                    case Right(stocks) => JsonUtil.toJson(stocks)
            }
        } yield resBody
        result.unsafeRunSync()
    })
    //
    get("/stock-search", (req, res) => {
        val word =  Option(req.queryParams("word")).get
        val data = StockService.make[IO](Stocks.make[IO]()).searchStock(word).unsafeRunSync()
        JsonUtil.toJson(data)
    })




    //    get("/report/:code", (req, res) => {
    //        val code = req.params(":code")
    //        val report = FinanceReports.make().getFinanceReport(code, FinanceReportType.BalanceSheet).unsafeRunSync()
    //        res.header("Content-Type", "application/json")
    //        JsonUtil.toJson(report)
    //    })

}

def testLog(): Unit = {
    import cats.effect.*
    import cats.implicits.*
    import org.typelevel.log4cats.Logger
    import org.typelevel.log4cats.slf4j.Slf4jLogger
    implicit def logger[F[_] : Sync]: Logger[F] = Slf4jLogger.getLogger[F]

    Logger[IO].info("Logging Start Something")
    println("...log....")
}

def testTraverse(): Unit ={
    import cats.instances.list.*
    import cats.syntax.parallel.*
    val ii = List(1, 2, 3)
    val ee:IO[List[Int]] =  ii.parTraverse(i => IO.blocking{
        println(s"thread => ${Thread.currentThread()}")
        i
    })
    val ee2:IO[List[Int]] = List(IO(1), IO(2), IO(3)).parSequence
    ee.unsafeRunSync()
}